package com.itheima.stock.service.impl;


import com.google.common.collect.Lists;
import com.itheima.stock.common.domain.StockInfoConfig;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBlockRtInfo;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.pojo.StockMarketIndexInfo;
import com.itheima.stock.pojo.StockRtInfo;
import com.itheima.stock.service.StockTimerTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    @Autowired
    private StockBusinessMapper stockBusinessMapper;
    @Autowired
    ParserStockInfoUtil parserStockInfoUtil;
    @Autowired
    StockRtInfoMapper stockRtInfoMapper;
    @Autowired
    StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public void getInnerMarketInfos() {

//        //1.定义采集的url接口
//        String url=stockInfoConfig.getMarketUrl() + String.join(",",stockInfoConfig.getInner());
//        //2.调用restTemplate采集数据
//        //2.1 组装请求头
//        HttpHeaders headers = new HttpHeaders();
//        //必须填写，否则数据采集不到
//        headers.add("Referer","https://finance.sina.com.cn/stock/");
//        headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
//        //2.2 组装请求对象
//        HttpEntity<Object> entity = new HttpEntity<>(headers);
//        //2.3 resetTemplate发起请求
//        String resString = restTemplate.postForObject(url, entity, String.class);
//        //log.info("当前采集的数据：{}",resString);
//        //3.数据解析（重要）
////        var hq_str_sh000001="上证指数,3267.8103,3283.4261,3236.6951,3290.2561,3236.4791,0,0,402626660,398081845473,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-04-07,15:01:09,00,";
////        var hq_str_sz399001="深证成指,12101.371,12172.911,11972.023,12205.097,11971.334,0.000,0.000,47857870369,524892592190.995,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2022-04-07,15:00:03,00";
//        String reg="var hq_str_(.+)=\"(.+)\";";
//        //编译表达式,获取编译对象
//        Pattern pattern = Pattern.compile(reg);
//        //匹配字符串
//        Matcher matcher = pattern.matcher(resString);
//        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
//        //判断是否有匹配的数值
//        while (matcher.find()){
//            //获取大盘的code
//            String marketCode = matcher.group(1);
//            //获取其它信息，字符串以逗号间隔
//            String otherInfo=matcher.group(2);
//            //以逗号切割字符串，形成数组
//            String[] splitArr = otherInfo.split(",");
//            //大盘名称
//            String marketName=splitArr[0];
//            //获取当前大盘的点数
//            BigDecimal openPoint=new BigDecimal(splitArr[1]);
//            //获取大盘的涨跌值
//            BigDecimal preClosePoint=new BigDecimal(splitArr[2]);
//            //获取大盘的涨幅
//            BigDecimal curPoint=new BigDecimal(splitArr[3]);
//            //获取大盘最高点
//            BigDecimal maxPoint=new BigDecimal(splitArr[4]);
//            //获取大盘的涨幅
//            BigDecimal minPoint=new BigDecimal(splitArr[5]);
//            //获取成交量
//            Long tradeAmt=Long.valueOf(splitArr[8]);
//            //获取成交金额
//            BigDecimal tradeVol=new BigDecimal(splitArr[9]);
//            //时间
//            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();
//            //组装entity对象
//            StockMarketIndexInfo info = StockMarketIndexInfo.builder()
//                    .id(idWorker.nextId() + "")
//                    .marketCode(marketCode)
//                    .marketName(marketName)
//                    .curPoint(curPoint)
//                    .openPoint(openPoint)
//                    .preClosePoint(preClosePoint)
//                    .maxPoint(maxPoint)
//                    .minPoint(minPoint)
//                    .tradeVolume(tradeVol)
//                    .tradeAmount(tradeAmt)
//                    .curTime(curTime)
//                    .build();
//            //收集封装的对象，方便批量插入
//            list.add(info);
//        }
//        log.info("采集的当前大盘数据：{}",list);
//        //批量插入
//        if (CollectionUtils.isEmpty(list)) {
//            return;
//        }
//


        //组装请求地址：
        String url = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());
        //组装请求对象
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39");
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
        //发送数据获取结果
        ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        //获取相应数据
        String body = resp.getBody();
        //System.out.println("Body:" + body);
        //封装数据到实体对象中
        //var hq_str_sh000001="上证指数,3068.0331,3054.9940,3084.2845,3086.0957,3059.2527,0,0,331737852,340942192653,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-05-13,15:01:12,00,";
        //String reg = "var hq_str_sh000001=\"上证指数,3068.0331,3054.9940,3084.2845,3086.0957,3059.2527,0,0,331737852,340942192653,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-05-13,15:01:12,00,";
        String reg = "var hq_str_(.*)=\"(.*)\";";
        Pattern compile = Pattern.compile(reg);
        Matcher matcher = compile.matcher(body);
        ArrayList<StockMarketIndexInfo> stocksMarketInfos = new ArrayList<>();
        while (matcher.find()) {
            String marketCode = matcher.group(1);
            String infos = matcher.group(2);
            //切割字符串数据，变成数组
            String[] infoArr = infos.split(",");
            //大盘名称
            String marketName = infoArr[0];
            //获取当前大盘的点数
            BigDecimal openPoint = new BigDecimal(infoArr[1]);
            //获取大盘的前收盘点
            BigDecimal preClosePoint = new BigDecimal(infoArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint = new BigDecimal(infoArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint = new BigDecimal(infoArr[4]);
            //获取大盘的涨幅
            BigDecimal minPoint = new BigDecimal(infoArr[5]);
            //获取成交量
            Long tradeAmt = Long.valueOf(infoArr[8]);
            //获取成交金额
            BigDecimal tradeVol = new BigDecimal(infoArr[9]);
            //时间
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(infoArr[30] + " " + infoArr[31]).toDate();

            //组装对象
            StockMarketIndexInfo marketIndexInfo = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId() + "")
                    .marketCode(marketCode)
                    .curTime(curTime)
                    .marketName(marketName)
                    .preClosePoint(preClosePoint)
                    .openPoint(openPoint)
                    .curPoint(curPoint)
                    .minPoint(minPoint)
                    .maxPoint(maxPoint)
                    .tradeAmount(tradeAmt)
                    .tradeVolume(tradeVol)
                    .build();

            stocksMarketInfos.add(marketIndexInfo);
        }
        //System.out.println("markets:" + stocksMarketInfos);
        if (CollectionUtils.isEmpty(stocksMarketInfos)) {
            log.info("当前采集股票数据为空");

        } else {
            int i = stockMarketIndexInfoMapper.insertBatch(stocksMarketInfos);
            log.info("{}条【大盘数据】插入完成",i);
        }

    }


    //个股数据的读取和存放
    @Override
    public void getStockRtIndex() {
        //获取代码集合
        List<String> allCodes = stockBusinessMapper.getAllCodes();
        //给所有股票代码添加前缀，使其符合接口规范sh,sz
        allCodes = allCodes.stream().map(code -> {
            code = code.startsWith("6") ? "sh" + code : "sz" + code;
            return code;
        }).collect(Collectors.toList());
        //System.out.println(allCodes);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39");
        httpHeaders.add("Referer", "https://finance.sina.com.cn/stock/");
        HttpEntity<Object> entity = new HttpEntity<>(httpHeaders);
        //分片，如每片20
        Lists.partition(allCodes, 500).stream().forEach(list -> {

//            //多线程。这种方法不推荐
//           new Thread(()->{
//               //
//           //。。。。
//           }).start();

            //线程池并发执行
            threadPoolTaskExecutor.submit(() -> {
                //地址：
                String url = stockInfoConfig.getMarketUrl() + String.join(",", list);
                //获取数据
                ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);

                //System.out.println(resp);
                String result = resp.getBody();
                //System.out.println(result);

                //用工具类解析相应的数据，并保存数据：
                List stockList = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);
                //System.out.println("stockList:" + stockList);
                //log.info("共有{}条", stockList.size());

                //保存到数据库：
                int i = stockRtInfoMapper.insertBatch(stockList);
                log.info("{}条【个股数据】插入完成",i);
            });


//           //单线程执行方式：
//            //地址：
//            String url = stockInfoConfig.getMarketUrl()+String.join(",",list);
//            //获取数据
//            ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
//
//            //System.out.println(resp);
//            String result = resp.getBody();
//            //System.out.println(result);
//
//            //用工具类解析相应的数据，并保存数据：
//            List stockList = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);
//            System.out.println(stockList);
//            log.info("共有{}条",stockList.size());
//
//            //保存到数据库：
//            int i = stockRtInfoMapper.insertBatch(stockList);
        });

    }

    //do:板块数据的读取和存放
    public void getStockBlockInfo() {
        //组装请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39");
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        //发送请求并得到相应
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        String url = "http://vip.stock.finance.sina.com.cn/q/view/newSinaHy.php";
        ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
        String body = resp.getBody();
        //System.out.println(body);
        //解析数据：
        List<StockBlockRtInfo> stockBlockRtInfos = parserStockInfoUtil.parse4StockBlock(body);
        //System.out.println("板块数据："+stockBlockRtInfos);
        //存入数据库：
        int i = stockBlockRtInfoMapper.insertBatch(stockBlockRtInfos);

        log.info("{}条【板块数据】插入完成",i);


    }
}
